package com.author.surface;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;

import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
import javax.swing.ListCellRenderer;

import com.author.document.style.DefaultStyleConstant;
import com.author.document.style.StyleChangeNotify;

public class DocumentStyleComboBox extends JComboBox implements ActionListener {
	/**
	 * All the style names and the font sizes corresponding to the style names
	 * declared inside this class are internal to the class. They will never be
	 * used to set style and font attributes outside this class.
	 */
	public static final String[]		DOCUMENT_STYLENAMES			= {
			"Heading1", "Heading2", "Heading3", "Heading4", "Normal",
			"Paragraph"											};

	/**
	 * The following fields indicate the font size that needs to be used with
	 * every font type e.g. A "Heading 1" style must be displayed with a font
	 * size of 24 etc.
	 */
	private static final int			HEADING_1_STYLE_FONT_SIZE	= 24;
	private static final int			HEADING_2_STYLE_FONT_SIZE	= 22;
	private static final int			HEADING_3_STYLE_FONT_SIZE	= 20;
	private static final int			HEADING_4_STYLE_FONT_SIZE	= 18;
	private static final int			NORMAL_STYLE_FONT_SIZE		= 16;
	private static final int			PARAGRAPH_STYLE_FONT_SIZE	= 16;

	/**
	 * Used to initialize the document style selection combo box. The 4th
	 * position is chosen because the "Normal" style occupies the 4th position
	 */
	public static int					DOCUMENT_STYLE_SELECTION	= 4;

	/** Current style associated with the document */
	public String						currentStyle				= DefaultStyleConstant.DEFAULT_STYLE;

	/**
	 * map keeps a mapping between the name of the style and the corresponding
	 * font size which is used for that particular style.
	 */
	private static Map<String, Integer>	fontSizeMap					= new HashMap<String, Integer>();
	static {
		fontSizeMap.put(DOCUMENT_STYLENAMES[0], HEADING_1_STYLE_FONT_SIZE);
		fontSizeMap.put(DOCUMENT_STYLENAMES[1], HEADING_2_STYLE_FONT_SIZE);
		fontSizeMap.put(DOCUMENT_STYLENAMES[2], HEADING_3_STYLE_FONT_SIZE);
		fontSizeMap.put(DOCUMENT_STYLENAMES[3], HEADING_4_STYLE_FONT_SIZE);
		fontSizeMap.put(DOCUMENT_STYLENAMES[4], NORMAL_STYLE_FONT_SIZE);
		fontSizeMap.put(DOCUMENT_STYLENAMES[5], PARAGRAPH_STYLE_FONT_SIZE);
	}

	/** CellRenderer and Scroll Pane for the document style combo box */
	private CellRenderer				cellrenderer;
	private JScrollPane					scrollpane;

	/** Width and Height of the style combo box */
	private static final int			DOCUMENT_STYLEBOX_WIDTH		= 190;
	private static final int			DOCUMENT_STYLEBOX_HEIGHT	= 25;

	/** Default Font name which will be used to display the document styles */
	private static final String			DEFAULT_FONT_NAME			= DefaultStyleConstant.DEFAULT_STYLE_FONT_NAME;

	protected DocumentStyleComboBox(Object[] stylenames) {
		super(stylenames);

		// Set size of the document style combo box
		setSize(new Dimension(DocumentStyleComboBox.DOCUMENT_STYLEBOX_WIDTH,
				DocumentStyleComboBox.DOCUMENT_STYLEBOX_HEIGHT));
		setPreferredSize(getSize());

		// Cell Renderer for the document style combo box
		cellrenderer = new CellRenderer();
		setRenderer(cellrenderer);

		/*
		 * Add scroll pane to the document style combo box
		 */
		scrollpane = new JScrollPane(this);
		scrollpane.setViewport(new JViewport());
		scrollpane.getViewport().setView(this);

		/*
		 * Set the default index position for the document style combo box
		 */
		int indexPos = DocumentStyleComboBox.DOCUMENT_STYLE_SELECTION;
		String selection = new String();
		setSelectedIndex(indexPos);
		selection = (String) this.getItemAt(indexPos);
		setFont(new Font(DEFAULT_FONT_NAME, Font.PLAIN,
				(Integer) fontSizeMap.get(DOCUMENT_STYLENAMES[indexPos])));

		/*
		 * Set tool tip and other related information for the document style
		 * combo box
		 */
		setToolTipText(selection + " Style");
		setFocusable(false);
		setVisible(true);
		addActionListener(this);
	}

	public void actionPerformed(ActionEvent e) {
		if (e.getSource() instanceof JComboBox) {
			JComboBox cb = (JComboBox) e.getSource();
			DocumentStyleComboBox.DOCUMENT_STYLE_SELECTION = cb
					.getSelectedIndex();

			// change current style to new style selected and inform style
			// change notifier object
			StyleChangeNotify styleChangeNotify = StyleChangeNotify
					.getStyleChangeNotify();
			String previousStyle = currentStyle;
			currentStyle = DocumentStyleComboBox.DOCUMENT_STYLENAMES[cb
					.getSelectedIndex()];
			styleChangeNotify.setDocumentStyleChange(previousStyle,
					currentStyle);
		}
	}

	public static int getFontSizeforStyle() {
		Object o = fontSizeMap
				.get(DOCUMENT_STYLENAMES[DocumentStyleComboBox.DOCUMENT_STYLE_SELECTION]);
		if (o == null) {
			return ((Integer) fontSizeMap.get("Normal"));
		}
		return ((Integer) o);
	}

	public static int getFontSizeforStyle(String stylename) {
		if ((stylename == null) || (stylename == "")) {
			return (Integer) fontSizeMap.get("Normal");
		}
		return (Integer) fontSizeMap.get(stylename);
	}

	protected class CellRenderer extends JLabel implements ListCellRenderer {
		/** Width and height of each individual cell of the Cell Renderer */
		private static final int	CELL_WIDTH	= 190;
		private static final int	CELL_HEIGHT	= 30;

		/** Font used by the Cell Renderer */
		private Font				font;

		protected CellRenderer() {
			/* Set cell renderer width and height */
			setSize(CELL_WIDTH, CELL_HEIGHT);
			setPreferredSize(getSize());

			// Set alignment properties of the cell renderer
			setOpaque(true);
			setHorizontalAlignment(LEFT);
			setVerticalAlignment(CENTER);

			// Set auxiliary display properties of the cell renderer
			setToolTipText("Select a Document Style");
		}

		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean hasFocus) {
			/*
			 * For the style name choosen by the user, get the corresponding
			 * size of the font
			 */
			String stylename = (String) value;
			int stylefontsize = (Integer) fontSizeMap.get(stylename);
			if (stylefontsize == -1) {
				return null;
			}

			/*
			 * If the user chooses a "heading" style then the font has to be
			 * displayed in BOLD.
			 */
			if (stylename.contains("Heading"))
				font = new Font(DEFAULT_FONT_NAME, Font.BOLD, stylefontsize);
			else {
				font = new Font(DEFAULT_FONT_NAME, Font.PLAIN, stylefontsize);
			}

			// Set font and text based on user choice
			setFont(font);
			setText((String) stylename);

			/*
			 * Sets the background and the foreground color when the component
			 * is selected by the user (when the user makes a choice)
			 */
			if (isSelected) {
				setBackground(list.getSelectionBackground());
				setForeground(list.getSelectionForeground());
			} else {
				setBackground(list.getBackground());
				setForeground(list.getForeground());
			}
			return this;
		}
	}

}
